package algebra.visitors.cursors;

import utils.exception.CoreReasoningException;
import utils.exception.OrderingDescriptionException;
import algebra.query.indexing.DescriptionIndex;
import algebra.query.indexing.IndexTreeNode;
import entities.assertion.ConceptAssertion;

public class CACursorDIOrderByUn extends CACursorDI {

	private boolean inited;
	private CACursorDIOrderByUn lcur = null, rcur = null;
	private IndexTreeNode[] three; 
	
	public CACursorDIOrderByUn(DescriptionIndex di, ConceptAssertion ca, IndexTreeNode root) {
		super(di, ca, root, false, null);
	}
	
	public void setMiddle(IndexTreeNode md){
		this.three[1] = md;
	}
	
	public IndexTreeNode getCursorRoot() {
		return this.root;
	}

	//0: init left cursor, 1: right cursor
	public void initSubCursor(ConceptAssertion query, IndexTreeNode myroot,int dir) {
		if (dir == 0 && myroot != null) {
			CACursorDIOrderByUn lcur = new CACursorDIOrderByUn(this.di, query, myroot);
			lcur.openCursor();
			this.lcur = lcur;
		}
		if (dir == 1 && myroot != null) {
			CACursorDIOrderByUn rcur = new CACursorDIOrderByUn(this.di, query, myroot);
			rcur.openCursor();
			this.rcur = rcur;
		}

	}

	public boolean isOpenSubCursor(int lr) {
		switch (lr) {
		case 0:
			return this.lcur != null;
		case 1:
			return this.rcur != null;
		default:
			return false;
		}
	}

	public void closeLeftSubCursor() {
		this.lcur = null;
	}

	public void closeRightSubCursor() {
		this.rcur = null;
	}

	public IndexTreeNode advanceSubCursor(int lr) {
		IndexTreeNode candidate = null;
		switch (lr) {
		case 0:
			if (this.lcur == null) {
				return null;
			}
			candidate = this.lcur.getNextResultNode();
			this.three[0] = candidate;
			if (candidate == null) {
				this.closeLeftSubCursor();
			}
			return candidate;
		case 1:
			if (this.rcur == null) {
				return null;
			}
			candidate = this.rcur.getNextResultNode();
			this.three[2] = candidate;
			if (candidate == null) {
				this.closeRightSubCursor();
			}
			return candidate;
		}
		return null;
	}


	@Override
	public boolean openCursor() {
		this.inited = false;
		this.three = new IndexTreeNode[3];
		return true;
	}

	@Override
	public ConceptAssertion getNextResult() {
		if (ca == null) {
			return null;
		}
		IndexTreeNode res = getNextResultNode();
		if (res != null) {
			return res.getNodeAssertion();
		}
		return null;
	}

	public IndexTreeNode getNextResultNode() {
		IndexTreeNode res = null;
		try {
			if(!inited){
				res = this.di.getNextNoSort(ca, this.root, star, null, this);
				inited = true;
			}else{
				res = this.getNextFromThree();
			}
			
		} catch (Exception e) {
			e.printStackTrace();
		} 
		return res;
	}
	
	public IndexTreeNode getNextFromThree()
			throws OrderingDescriptionException, CoreReasoningException {
		IndexTreeNode[] three = this.three;
		IndexTreeNode min = null;
		if(three[0] != null){
			min = this.three[0];
			if (this.isOpenSubCursor(0)) {
				 this.advanceSubCursor(0);
			}
			return min;
		}else if(three[1] != null){
			min = three[1];
			this.three[1] = null;
			return min;
		}else if(three[2] != null){
			min = three[2];
			if (this.isOpenSubCursor(1)) {
				this.advanceSubCursor(1);
			}
			return min;
		}else{
			return null;
		}
		
	}
	


	@Override
	public String toString() {
		return this.root.getID().toString();
	}

	public boolean repetition() {
		return this.inited;
	}


}
